<?php

if (!defined('PHOX') or !constant('PHOX')) die('Direct access not allowed!');

/**
 * The Front Controller 
 * 
 * The front controller’s job is to parse the URL and to instantiate the controller and invoke the 
 * action method. This is a singleton class, which is responsible for the application’s program flow.
 * 
 * The theory of operation is that URLs follow the format /controller/action/key1/value1/ 
 * Once the URL has been parsed, it uses the reflection API to
 * invoke the action method on the BaseController implementing class
 *
 * @package controller
 * @version 0.1
 * @author Pedro Eugénio <voxmachina@sapo.pt> 
 * @license GPL v.3
 */
class FrontController
{

  protected $controller, $action, $params, $body;
  static $instance;

 /**
  * __construct 
  * 
  * @return void
  */
  private function __construct()
  {
    $request  = $_SERVER['REQUEST_URI'];
    $splits   = explode( '/' , trim( $request , '/' ) );
   
    $this->controller = !empty( $splits[0] ) ? $splits[0] : DEFAULT_CONTROLLER;
    $this->action     = !empty( $splits[1] ) ? $splits[1] : DEFAULT_ACTION;

    if( !empty( $splits[2] ) )
    {
      $keys = $values = array();
  
      for( $idx = 2 , $cnt = count( $splits ); $idx<$cnt; $idx++ )
      {
        if( $idx % 2 == 0 )
        {
          // if is even, is key
          $keys[]   = $splits[$idx];
        } else {
          // if is odd, is value
          $values[] = $splits[$idx];
        }
      }
      $this->params = array_combine( $keys , $values );
    }
  }

 /**
  * getInstance 
  * 
  * @return FrontController instance 
  */
  public static function getInstance()
  {
    if( !(self::$instance instanceof self) )
    {
      self::$instance = new self();
    }
    return self::$instance;
  }

 /**
  * route 
  * 
  * @return void
  */
  public function route()
  {
    if( class_exists( $this->getController() ) )
    {
      $rc = new ReflectionClass( $this->getController() );
      
      if( $rc->implementsInterface( 'BaseController' ) )
      {
        if( $rc->hasMethod( $this->getAction () ) )
        {
          $controller = $rc->newInstance();
          $method     = $rc->getMethod( $this->getAction() );
          $method->invoke($controller);
        } else {
          throw new Exception( 'Action' );
        }
      } else {
        throw new Exception( 'Interface' );
      }
    } else {
      throw new Exception( 'Controller' );
    }
  }

 /**
  * getParams 
  * 
  * @return mixed parameters
  */
  public function getParams()
  {
    return $this->params;
  }

 /**
  * getController 
  * 
  * @return controller
  */
  public function getController()
  {
    return $this->controller;
  }

 /**
  * getAction 
  * 
  * @return action
  */
  public function getAction()
  {
    return $this->action;
  }

 /**
  * getBody 
  * 
  * @return body
  */
  public function getBody()
  {
    return $this->body;
  }

 /**
  * setBody 
  * 
  * @param mixed $body 
  * @return void
  */
  public function setBody( $body )
  {
    $this->body = $body;
  }

}

?>
